#include "ArrayEditor.h"
#include "global.h"

#define ENTRY_STATE_OK      0
#define ENTRY_STATE_WARNING 1
#define ENTRY_STATE_ERROR   2

ArrayEditor::ArrayEditor(BitArray *array, bool editable, QObject *parent) :
    QObject(parent), mpArray(array), mEditable(editable)
{

}


//-------------------------------------------------------------------

ArraySizeEditor::ArraySizeEditor(BitArray *array, bool editable, QObject *parent) :
    ArrayEditor(array, editable, parent)
{
    sizeSpinBox = new QSpinBox();
    cBoxSizeMult = new QComboBox();
    chkBoxSizeFix = new QCheckBox("fix");

    mGroupBox = new QGroupBox("Size");
    QHBoxLayout *boxLayout = new QHBoxLayout(mGroupBox);

    cBoxSizeMult->addItem("Bit");
    cBoxSizeMult->addItem("Byte");

    sizeSpinBox->setEnabled(editable);
    cBoxSizeMult->setEnabled(editable);

    cBoxSizeMult->setCurrentIndex(1);
    sizeSpinBox->setRange(0, MAX_ARRAY_SIZE/8);

    boxLayout->addWidget(sizeSpinBox);
    boxLayout->addWidget(cBoxSizeMult);
    if(editable)
    {
        boxLayout->addWidget(chkBoxSizeFix);
        chkBoxSizeFix->setChecked(true);
        mpArray->setResizeEnable(false);
    }
    boxLayout->setContentsMargins(5, 0, 5, 5);

    connect(sizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(sizeValChanged(int)));
    connect(cBoxSizeMult, SIGNAL(currentIndexChanged(int)), this, SLOT(sizeMultChanged(int)));
    connect(chkBoxSizeFix, SIGNAL(clicked()), this, SLOT(chkBoxSizeFixClicked()));
}

void ArraySizeEditor::sizeValChanged(int size)
{
    int mult = 1 << (cBoxSizeMult->currentIndex()*3);

    if(chkBoxSizeFix->isChecked())
        mpArray->setResizeEnable(true);

    if(size > MAX_ARRAY_SIZE/8)
        cBoxSizeMult->setEnabled(false);
    else
        cBoxSizeMult->setEnabled(mEditable);

    mpArray->resize(size*mult);

    if(chkBoxSizeFix->isChecked())
        mpArray->setResizeEnable(false);

    emit valueChanged();
}

void ArraySizeEditor::sizeMultChanged(int idx)
{
    if(idx == 0)
        sizeSpinBox->setRange(0, MAX_ARRAY_SIZE);
    else
        sizeSpinBox->setRange(0, MAX_ARRAY_SIZE/8);

    if(chkBoxSizeFix->isChecked())
        mpArray->setResizeEnable(true);

    int mult = 1 << (idx*3);
    mpArray->resize(sizeSpinBox->value() * mult);

    if(chkBoxSizeFix->isChecked())
        mpArray->setResizeEnable(false);

    emit valueChanged();
}

void ArraySizeEditor::chkBoxSizeFixClicked()
{
    mpArray->setResizeEnable(!chkBoxSizeFix->isChecked());
}

void ArraySizeEditor::updateView()
{
    disconnect(sizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(sizeValChanged(int)));
    disconnect(cBoxSizeMult, SIGNAL(currentIndexChanged(int)), this, SLOT(sizeMultChanged(int)));

    cBoxSizeMult->setCurrentIndex(0);
    sizeSpinBox->setRange(0, MAX_ARRAY_SIZE);

    int div = 1 << (cBoxSizeMult->currentIndex()*3);
    sizeSpinBox->setValue(mpArray->size()/div);

    connect(sizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(sizeValChanged(int)));
    connect(cBoxSizeMult, SIGNAL(currentIndexChanged(int)), this, SLOT(sizeMultChanged(int)));
}



//-------------------------------------------------------------------

ArrayLineEditor::ArrayLineEditor(BitArray *array, bool editable, QObject *parent) :
    ArrayEditor(array, editable, parent)
{
    mpLineEdit = new QLineEdit();
    mPaletteNormal = mpLineEdit->palette();
    mpLineEdit->setAlignment(Qt::AlignRight);
    mpLineEdit->setFont(QFont("Courier"));
    mpLineEdit->setReadOnly(!editable);
    connect(mpLineEdit, SIGNAL(textEdited(QString)), this, SLOT(textEditedSlot(QString)));
}

void ArrayLineEditor::updateView()
{
    setEntryState(ENTRY_STATE_OK);
    updateCustomView();
}


void ArrayLineEditor::setEntryState(int state)
{
    if(state == ENTRY_STATE_OK)
    {
        mpLineEdit->setPalette(mPaletteNormal);
    }
    else if(state == ENTRY_STATE_WARNING)
    {
        QPalette p = mpLineEdit->palette();
        p.setColor(QPalette::Base, QColor(Qt::yellow));
        mpLineEdit->setPalette(p);
    }
    else if(state == ENTRY_STATE_ERROR)
    {
        QPalette p = mpLineEdit->palette();
        p.setColor(QPalette::Base, QColor(Qt::red));
        mpLineEdit->setPalette(p);
    }
}






//-------------------------------------------------------------------

ArrayHexEditor::ArrayHexEditor(BitArray *array, bool editable, QWidget *parent) :
    ArrayLineEditor(array, editable, parent)
{

}

void ArrayHexEditor::updateCustomView()
{
    mpLineEdit->setText(mpArray->toHexString(false));
}

void ArrayHexEditor::textEditedSlot(QString text)
{
    if(!mpArray->fromHexString(text.trimmed().toLower()))
        setEntryState(ENTRY_STATE_ERROR);
    else
    {
        if(text.trimmed().length() != mpArray->size()/4)
            setEntryState(ENTRY_STATE_WARNING);
        else
            setEntryState(ENTRY_STATE_OK);
        emit valueChanged();
    }
}

//-------------------------------------------------------------------
ArrayBinEditor::ArrayBinEditor(BitArray *array, bool editable, QWidget *parent) :
    ArrayLineEditor(array, editable, parent)
{

}

void ArrayBinEditor::updateCustomView()
{
    mpLineEdit->setText(mpArray->toBinString(false));
}

void ArrayBinEditor::textEditedSlot(QString text)
{
    if(!mpArray->fromBinString(text.trimmed().toLower()))
        setEntryState(ENTRY_STATE_ERROR);
    else
    {
        if(text.trimmed().length() != mpArray->size())
            setEntryState(ENTRY_STATE_WARNING);
        else
            setEntryState(ENTRY_STATE_OK);
        emit valueChanged();
    }
}

//-------------------------------------------------------------------
ArrayDecEditor::ArrayDecEditor(BitArray *array, bool editable, QWidget *parent) :
    ArrayLineEditor(array, editable, parent)
{

}

void ArrayDecEditor::updateCustomView()
{
    mpLineEdit->setText(mpArray->toDecString());
}

void ArrayDecEditor::textEditedSlot(QString text)
{
    if(!mpArray->fromDecString(text.trimmed().toLower()))
        setEntryState(ENTRY_STATE_ERROR);
    else
    {
        setEntryState(ENTRY_STATE_OK);
        emit valueChanged();
    }
}

//-------------------------------------------------------------------
ArrayAsciiEditor::ArrayAsciiEditor(BitArray *array, bool editable, QWidget *parent) :
    ArrayLineEditor(array, editable, parent)
{

}

void ArrayAsciiEditor::updateCustomView()
{
    mpLineEdit->setText(mpArray->toAsciiString());
}

void ArrayAsciiEditor::textEditedSlot(QString text)
{
    if(!mpArray->fromAsciiString(text.trimmed()))
        setEntryState(ENTRY_STATE_ERROR);
    else
    {
        if(text.trimmed().length() != mpArray->size()/8)
            setEntryState(ENTRY_STATE_WARNING);
        else
            setEntryState(ENTRY_STATE_OK);
        emit valueChanged();
    }
}
